package com.piece.admin.service;

import com.piece.admin.model.TbSmsChannel;
import com.piece.admin.model.TbSmsTemplate;
import com.piece.admin.repository.TbSmsTemplateRepository;
import com.piece.core.framework.constant.ExceptionConstants;
import com.piece.core.framework.enums.StatusType;
import com.piece.core.framework.exception.ErrorCode;
import com.piece.core.framework.exception.FrameWorkException;
import com.piece.core.framework.support.response.AjaxResponse;
import com.piece.core.framework.util.collection.MapUtil;
import com.piece.core.framework.util.net.HtmlUtil;
import com.piece.core.framework.util.string.JsonUtil;
import com.piece.core.jpa.repository.BaseService;
import com.piece.core.message.client.SmsClient;
import com.piece.core.message.client.SmsClientFactory;
import com.piece.core.message.enums.SmsChannelType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;

@Slf4j
@Service
@Transactional
public class TbSmsTemplateService extends BaseService<TbSmsTemplate, String> {

    @Resource
    private TbSmsTemplateRepository tbSmsTemplateRepository;

    @Resource
    private TbSmsChannelService tbSmsChannelService;

    @Resource
    private SmsClientFactory smsClientFactory;

    @PostConstruct
    public void initRepository() {
        setRepository(tbSmsTemplateRepository);
    }

    @Override
    public TbSmsTemplate insertOrUpdate(TbSmsTemplate template) throws Exception {
        // 校验短信渠道
        TbSmsChannel channel = checkSmsChannel(template.getChannelCode());
        // 校验短信编码是否重复
        if (!checkTemplateCodeUnique(template.getId(), template.getChannelCode(), template.getTemplateCode())) {
            throw new FrameWorkException(new ErrorCode(ExceptionConstants.REPEAT, "模板编码【" + template.getChannelCode() + "】"));
        }
        // 校验短信模板
        checkTemplateId(channel.getCode(), template.getTemplateId());

        template.setParams(parseTemplateContentParams(template.getContent()));
        if (null == template.getId()) {
            template = tbSmsTemplateRepository.insert(template);
        } else {
            tbSmsTemplateRepository.update(template);
        }

        return template;
    }

    private String parseTemplateContentParams(String content) {
        // 匹配 {} 中的变量
        List<String> params = HtmlUtil.grepTextByPattern(content, "\\{(.*?)}", 1);
        return JsonUtil.toJson(params);
    }

    @Override
    public void delete(Serializable id) throws Exception {
        tbSmsTemplateRepository.updateByProperties("id", id, "status", StatusType.DELETE.getCode());
    }

    @Override
    public int delete(Serializable[] ids) throws Exception {
        return tbSmsTemplateRepository.updateByProperties("Q_id_L_IN", ids, "status", StatusType.DELETE.getCode());
    }

    /**
     * 获取短信API模板编号
     *
     * @param channelCode  短信渠道编号
     * @param templateCode 模板编码
     */
    public String getTemplateId(String channelCode, String templateCode) {
        List<TbSmsTemplate> templates = tbSmsTemplateRepository.findByCondition(MapUtil.builder(new HashMap<String, Object>())
                .put("channelCode", channelCode)
                .put("templateCode", templateCode)
                .build(), null);
        return templates.size() > 0 ? templates.get(0).getTemplateId() : null;
    }

    /**
     * 验证短信渠道是否存在
     */
    public TbSmsChannel checkSmsChannel(String channelCode) {
        TbSmsChannel channel = tbSmsChannelService.findOneByCondition(MapUtil.builder(new HashMap<String, Object>())
                .put("code", channelCode)
                .build());
        if (null == channel) {
            throw new FrameWorkException(new ErrorCode(ExceptionConstants.NOT_EXIST, "短信渠道【" + channelCode + "】"));
        }

        return channel;
    }

    /**
     * 判断模板编码是否重复
     */
    public boolean checkTemplateCodeUnique(Long id, String channelCode, String templateCode) {
        String hql = "from TbSmsTemplate where channelCode = ?0 and templateCode = ?1 and status = ?2";
        Object[] params = new Object[]{channelCode, templateCode, StatusType.NORMAL.getCode()};
        if (null != id) {
            hql += " and id != ?3";
            params = new Object[]{channelCode, templateCode, StatusType.NORMAL.getCode(), id};
        }
        long count = tbSmsTemplateRepository.count(hql, params, true);
        return count <= 0;
    }

    /**
     * 校验短信平台模板是否有效
     */
    public void checkTemplateId(String channelCode, String templateId) {
        SmsClient client = smsClientFactory.getClient(SmsChannelType.getByCode(channelCode));
        Assert.notNull(client, String.format("短信渠道(%d) 不存在", channelCode));
        AjaxResponse response = client.getSmsTemplate(templateId);
        if (response.getCode() == 500) {
            throw new FrameWorkException(new ErrorCode(ExceptionConstants.NOT_EXIST, "短信平台【" + SmsChannelType.getByCode(channelCode).getName() + "】模板 -【" + templateId + "】"));
        }
    }

    /**
     * 发送短信通知
     *
     * @param mobile          手机号
     * @param template        发送模板
     */
    public void send(String mobile, TbSmsTemplate template) {
        SmsChannelType channelType = SmsChannelType.getByCode(template.getChannelCode());
        smsClientFactory.getClient(channelType).sendSms(mobile, template.getTemplateId(), JsonUtil.toLinkedMap(template.getParams()));
    }
}
